package com.tbit.uqbike.service.business.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tbit.uqbike.constant.BatteryConstant;
import com.tbit.uqbike.constant.BatteryStateConstant;
import com.tbit.uqbike.manager.exception.BaseException;
import com.tbit.uqbike.object.pojo.*;
import com.tbit.uqbike.object.pojo.dto.BatteryMessageDownloadDTO;
import com.tbit.uqbike.object.pojo.dto.BatteryMsgDTO;
import com.tbit.uqbike.object.pojo.vo.BatchOperationMsgVO;
import com.tbit.uqbike.object.pojo.vo.BatteryMsgVO;
import com.tbit.uqbike.object.pojo.vo.BatteryVO;
import com.tbit.uqbike.object.value.LoginInfo;
import com.tbit.common.entity.view.PageResult;
import com.tbit.common.entity.view.Result;
import com.tbit.uqbike.service.business.BatteryMsgService;
import com.tbit.uqbike.webmanager.dao.core.AccountUserDao;
import com.tbit.uqbike.webmanager.dao.core.BatteryMsgDao;
import com.tbit.uqbike.webmanager.dao.core.BmsDao;
import com.tbit.uqbike.webmanager.dao.core.MachineDao;
import com.tbit.uqbike.webmanager.dao.log.BatteryLogDao;
import com.tbit.uqbike.webmanager.dao.log.BmsAbnormalDao;
import com.tbit.uqbike.webmanager.util.csv.CsvExportUtils;
import com.tbit.uqbike.webmanager.util.excel.ExcelUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 电池厂商信息接口实现类
 *
 * @Author:BUGTian
 * @DATE: 2022/5/13
 */
@Service
public class BatteryMsgServiceImpl implements BatteryMsgService {

    @Autowired
    private BatteryMsgDao batteryMsgDao;

    @Autowired
    private AccountUserDao accountUserDao;

    @Autowired
    private BatteryLogDao batteryLogDao;

    @Autowired
    private BmsDao bmsDao;

    @Autowired
    private BmsAbnormalDao bmsAbnormalDao;

    @Resource
    private MachineDao machineDao;

    @Autowired
    private CsvExportUtils csvExportUtils;

    @Override
    public PageResult<BatteryMsgVO> queryPage(Integer accountId, Integer page, Integer size, String batteryNO, Integer batteryModelId, Date startTime, Date endTime, Integer state, String userCode) {
        //条件查询查询电池厂商信息
        PageInfo<BatteryMsgVO> pageInfo = PageHelper.startPage(page, size).doSelectPageInfo(() -> batteryMsgDao.query(accountId, batteryNO, batteryModelId, startTime, endTime, state, userCode));
        List<BatteryMsgVO> list = pageInfo.getList();
        Map<Integer, AccountUser> accountUserMap = accountUserDao.getByType(accountId, false)
                .stream()
                .collect(Collectors.toMap(AccountUser::getAccountUserId, x -> x));
        //添加用户解析
        for (BatteryMsgVO batteryMsgVO : list) {
            AccountUser accountUser = accountUserMap.get(batteryMsgVO.getAddAccountUserId());
            batteryMsgVO.setAddAccountUserName(accountUser == null ? "" : accountUser.getName());
            batteryMsgVO.setAddAccountUserPhone(accountUser == null ? "" : accountUser.getPhone());
            if (Objects.nonNull(batteryMsgVO.getUpdateTime())){
                batteryMsgVO.setResidenceTime((DateUtil.between(new Date(), batteryMsgVO.getUpdateTime(), DateUnit.DAY)) + "天");
            }else {
                batteryMsgVO.setResidenceTime((DateUtil.between(new Date(), batteryMsgVO.getAddTime(), DateUnit.DAY)) + "天");
            }

        }
        return new PageResult<>(page, size, pageInfo.getTotal(), pageInfo.getPages(), list);
    }

    @Override
    public String batteryMessageDownloadCsv(BatteryMessageDownloadDTO downloadDTO) {
        List<BatteryMsgVO> dataList = batteryMsgDao.query(downloadDTO.getAccountId(), downloadDTO.getBatteryNO(),
                downloadDTO.getBatteryModelId(), downloadDTO.getStartTime(), downloadDTO.getEndTime(), downloadDTO.getState(), downloadDTO.getUserCode());
        if (CollectionUtils.isNotEmpty(dataList)) {
            Map<Integer, AccountUser> accountUserMap = accountUserDao.getByType(downloadDTO.getAccountId(), false)
                    .stream()
                    .collect(Collectors.toMap(AccountUser::getAccountUserId, x -> x));
            for (BatteryMsgVO batteryMsgVO : dataList) {
                AccountUser accountUser = accountUserMap.get(batteryMsgVO.getAddAccountUserId());
                batteryMsgVO.setAddAccountUserName(accountUser == null ? "" : accountUser.getName());
                batteryMsgVO.setAddAccountUserPhone(accountUser == null ? "" : accountUser.getPhone());

                Date addTime = batteryMsgVO.getAddTime();
                Date updateTime = Optional.ofNullable(batteryMsgVO.getUpdateTime()).orElse(addTime);
                if (Objects.nonNull(batteryMsgVO.getUpdateTime())){
                    batteryMsgVO.setResidenceTime((DateUtil.between(new Date(), batteryMsgVO.getUpdateTime(), DateUnit.DAY)) + "天");
                }else {
                    batteryMsgVO.setResidenceTime((DateUtil.between(new Date(), batteryMsgVO.getAddTime(), DateUnit.DAY)) + "天");
                }
                batteryMsgVO.setUseBms(batteryMsgVO.getUseBms() == null ? 0 : batteryMsgVO.getUseBms());

            }
        }
        //获取临时路径
        File tempFile = csvExportUtils.getTempFile();
        try {
            File file = csvExportUtils.exportCsv(BatteryMsgVO.class, tempFile, downloadDTO.getFileName(), dataList);
            String uploadFileName = UUID.randomUUID().toString().replace("-", "");
            //压缩上传oss
            return csvExportUtils.uploadZip(tempFile, uploadFileName, file);
        } finally {
            //删除本地文件
            FileUtil.del(tempFile);
        }
    }

    @Override
    public Result<BatchOperationMsgVO<String>> batchAdd(BatteryMsgDTO batteryMsgDTO, LoginInfo loginInfo) {
        Integer accountId = batteryMsgDTO.getAccountId();
        if (accountId == null) {
            throw new BaseException("区域id不能为空");
        }
        BatchOperationMsgVO<String> batchOperationMsgVO = new BatchOperationMsgVO<>();
        Integer batteryModelId = batteryMsgDTO.getBatteryModelId();
        List<String> successList = new LinkedList<>();
        List<String> failList = new LinkedList<>();
        Date now = new Date();
        for (String batteryNO : batteryMsgDTO.getBatteryNOs()) {
            String batteryNOInDB = batteryMsgDao.queryByBatteryNO(batteryNO);
            if (StringUtils.isEmpty(batteryNOInDB)) {
                Integer accountUserId = loginInfo.getAccountUserId();
                batteryMsgDao.insert(batteryNO, accountId, batteryModelId, accountUserId, now);
                Integer batteryId = batteryMsgDao.selectBatteryIdByNO(batteryNO);
                batteryLogDao.insert(accountId, batteryId, batteryNO, BatteryStateConstant.ADD, accountUserId, now, null);
                successList.add(batteryNO);
            } else {
                failList.add(batteryNO);
            }
        }
        //成功添加的电池
        batchOperationMsgVO.setSuccessList(successList)
                //电池编号重复的电池
                .setFailList(failList);
        return Result.success(batchOperationMsgVO);
    }

    @Override
    public Result delete(LoginInfo login, Integer... batteryIds) {
        StringBuilder stringBuilder = new StringBuilder();
        for (Integer batteryId : batteryIds) {
            //查询电池是否绑定
            String batteryNO = batteryMsgDao.queryBoundByBatteryID(batteryId);
            if (StringUtils.isNotBlank(batteryNO)) {
                //未绑定
                BatteryMsg batteryMsg = batteryMsgDao.selectBatterById(batteryId);
                batteryMsgDao.deleteByBatteryId(batteryId);
                List<String> deleteNo = new ArrayList<>();
                deleteNo.add(batteryMsg.getBatteryNO());
                bmsDao.deleteBmsBattery(deleteNo);
                bmsAbnormalDao.deleteBmsBatteryAbNormal(deleteNo);
                batteryLogDao.insert(batteryMsg.getAccountId(), batteryId, batteryMsg.getBatteryNO(), BatteryStateConstant.DELETE, login.getAccountUserId(), new Date(), null);
            } else {
                stringBuilder.append(batteryNO + ",");
            }
        }
        String s = stringBuilder.toString();
        if (StringUtils.isEmpty(s)) {
            return Result.success();
        } else {
            //截取掉最后的,
            s = s.substring(0, s.lastIndexOf(","));
            return Result.success(String.format("操作成功，失败的编号为%s，原因：编号不存在", s), null);
        }
    }

    @Override
    public Result<BatchOperationMsgVO<String>> deleteByBatteryNo(LoginInfo login, String batteryNos,Integer accountId) {
        BatchOperationMsgVO<String> batchOperationMsgVO = new BatchOperationMsgVO<>();
        if (StringUtils.isBlank(batteryNos)) {
            return Result.success(batchOperationMsgVO);
        }
        for (String batteryNo : batteryNos.split(",")) {
            if (StringUtils.isBlank(batteryNo)) {
                batchOperationMsgVO.putAbnormalValue(batteryNo);
                continue;
            }
            BatteryMsg batteryMsg = batteryMsgDao.selectBatterMsgByNoAndAccountId(batteryNo,accountId);
            if (batteryMsg == null) {
                batchOperationMsgVO.putAbnormalValue(batteryNo);
                continue;
            }
            //未绑定
            batteryMsgDao.deleteByBatteryId(batteryMsg.getBatteryId());
            List<String> deleteNo = new ArrayList<>();
            deleteNo.add(batteryMsg.getBatteryNO());
            bmsDao.deleteBmsBattery(deleteNo);
            bmsAbnormalDao.deleteBmsBatteryAbNormal(deleteNo);
            batteryLogDao.insert(batteryMsg.getAccountId(), batteryMsg.getBatteryId(), batteryMsg.getBatteryNO(), BatteryStateConstant.DELETE, login.getAccountUserId(), new Date(), null);
            batchOperationMsgVO.putSuccessValue(batteryNo);
        }
        return Result.success(batchOperationMsgVO);
    }


    /**
     * 批量操作电池状态
     * @param login login
     * @param accountId 区域id
     * @param batteryNo 电池编号
     * @param type 1:标记丢失 2:删除丢失标记
     * @return result
     */
    @Override
    public Result<BatchOperationMsgVO<String>> lose(LoginInfo login, Integer accountId, Integer type, String batteryNo, String remark) {
        BatchOperationMsgVO<String> resultVo = new BatchOperationMsgVO<>();
        //解析电池编号
        Set<String> batteryNoList = Arrays.stream(batteryNo.split(",")).collect(Collectors.toSet());
        //获取电池数据
        List<BatteryMsgVO> list = batteryMsgDao.queryByNOList(accountId, batteryNoList);
        if (CollectionUtil.isEmpty(list)){
            return Result.error("电池编号不存在");
        }

        // 设备编号
        List<String> userCodeList = list.stream()
                .map(BatteryMsgVO::getUserCode)
                .filter(Objects::nonNull)
                .filter(userCode -> !userCode.isEmpty())
                .collect(Collectors.toList());
        // 电池编号
        List<String> batteryNos = new ArrayList<>();

        //批量修改电池信息
        List<BatteryVO> batteryVOList = new ArrayList<>();
        //批量新增电池日志
        List<BatteryLog> batteryLogList = new ArrayList<>();
        List<String> failList = new ArrayList<>();

        if (1 == type) {
            //车辆丢失、电池丢失
            List<MachineLose> machineLoseList = new ArrayList<>();
            List<BatteryLose> batteryLoseList = new ArrayList<>();
            Map<String, Map<String, Object>> userCodeMap = new HashMap<>();
            if (CollectionUtil.isNotEmpty(userCodeList)) {
                userCodeMap = machineDao.queryByUserCode(userCodeList);
            }

            for (BatteryMsgVO batteryMsgVO : list) {
                //记录电池编号
                batteryNos.add(batteryMsgVO.getBatteryNO());
                //已标记丢失 默认失败 直接返回
                if (BatteryConstant.Battery_State_DS.equals(batteryMsgVO.getState())){
                    failList.add(batteryMsgVO.getBatteryNO());
                    continue;
                }
                //封装电池对象
                packBatteryVo(login, remark, batteryVOList, batteryMsgVO, BatteryConstant.Battery_State_DS);

                //新增电池丢失记录
                BatteryLose batteryLose = new BatteryLose();
                batteryLose.setAccountId(accountId)
                        .setAddMan("管理员")
                        .setBatteryId(Integer.parseInt(batteryMsgVO.getBatteryId()))
                        .setBatteryNO(batteryMsgVO.getBatteryNO())
                        .setLoseTime(DateUtil.now())
                        .setReason(remark + "电池丢失，上报车辆丢失")
                        .setRemark(remark);
                batteryLoseList.add(batteryLose);
                //封装电池日志
                packBatteryLog(login, accountId, remark, batteryLogList, batteryMsgVO, BatteryConstant.Battery_Type_DS);

                //电池绑定了车辆 -> 车辆上报丢失
                Map<String, Object> machine = userCodeMap.get(batteryMsgVO.getUserCode());
                if (Objects.nonNull(batteryMsgVO.getUserCode()) && machine != null) {
                    MachineLose machineLose = new MachineLose();
                    machineLose.setAccountId(accountId)
                            .setAddMan("管理员")
                            .setMachineId(Objects.nonNull(machine.get("machineId")) ? Integer.parseInt(machine.get("machineId").toString()) : null)
                            .setMachineNO(Objects.nonNull(machine.get("machineNO")) ? machine.get("machineNO").toString() : null)
                            .setUserCode(batteryMsgVO.getUserCode())
                            .setLoseTime(DateUtil.now())
                            .setReason(batteryMsgVO.getBatteryNO() + "电池丢失，上报车辆丢失")
                            .setRemark(remark);
                    machineLoseList.add(machineLose);
                }

            }

            //批量新增电池丢失记录、车辆丢失记录和日志
            if (CollectionUtil.isNotEmpty(machineLoseList)){
                machineDao.batchAddMachineLose(machineLoseList);
            }
            if (CollectionUtil.isNotEmpty(batteryLoseList)){
                batteryMsgDao.batchAddBatteryLose(batteryLoseList);
            }
            //批量删除电池分组
            if (CollectionUtil.isNotEmpty(batteryNos)){
                batteryMsgDao.batchDelBatteryGroup(batteryNos);
            }
        } else if (2 == type) {

            for (BatteryMsgVO batteryMsgVO : list) {
                //取消标记 默认状态不是丢失 不允许取消
                if (!BatteryConstant.Battery_State_DS.equals(batteryMsgVO.getState())){
                    failList.add(batteryMsgVO.getBatteryNO());
                    continue;
                }
                //修改电池状态
                packBatteryVo(login, remark, batteryVOList, batteryMsgVO, BatteryConstant.Battery_State_DRK);
                //电池日志
                packBatteryLog(login, accountId, remark, batteryLogList, batteryMsgVO, BatteryConstant.Battery_Type_XH);
                //记录电池编号
                batteryNos.add(batteryMsgVO.getBatteryNO());
            }

            //批量删除车辆丢失记录
            if (CollectionUtil.isNotEmpty(userCodeList)){
                machineDao.batchDelByUserCode(userCodeList);
            }
            //批量删除电池丢失记录
            if (CollectionUtil.isNotEmpty(batteryNos)){
                batteryMsgDao.batchDelByBatteryNo(batteryNos);
            }
        }
        //批量修改电池状态
        if (CollectionUtil.isNotEmpty(batteryVOList)){
            batteryMsgDao.batchUpdateByNo(batteryVOList);
        }
        //批量新增电池操作日志
        if (CollectionUtil.isNotEmpty(batteryLogList)) {
            batteryLogDao.batchAddBatteryLog(batteryLogList);
        }
        failList.addAll(batteryNoList.stream().filter(batteryNO -> !batteryNos.contains(batteryNO)).collect(Collectors.toList()));
        resultVo.setFailList(failList);
        return Result.success(resultVo);
    }

    /**
     * 电池厂商信息导出excel
     * @param downloadDTO 入参
     * @return excel
     */
    @Override
    public Result<Object> batteryMessageDownload(BatteryMessageDownloadDTO downloadDTO) {
        List<BatteryMsgVO> dataList = batteryMsgDao.query(downloadDTO.getAccountId(), downloadDTO.getBatteryNO(),
                downloadDTO.getBatteryModelId(), downloadDTO.getStartTime(), downloadDTO.getEndTime(), downloadDTO.getState(), downloadDTO.getUserCode());
        if (CollectionUtils.isNotEmpty(dataList)) {
            Map<Integer, AccountUser> accountUserMap = accountUserDao.getByType(downloadDTO.getAccountId(), false)
                    .stream()
                    .collect(Collectors.toMap(AccountUser::getAccountUserId, x -> x));
            for (BatteryMsgVO batteryMsgVO : dataList) {
                AccountUser accountUser = accountUserMap.get(batteryMsgVO.getAddAccountUserId());
                batteryMsgVO.setAddAccountUserName(accountUser == null ? "" : accountUser.getName());
                batteryMsgVO.setAddAccountUserPhone(accountUser == null ? "" : accountUser.getPhone());

                Date addTime = batteryMsgVO.getAddTime();
                Date updateTime = Optional.ofNullable(batteryMsgVO.getUpdateTime()).orElse(addTime);
                if (Objects.nonNull(batteryMsgVO.getUpdateTime())){
                    batteryMsgVO.setResidenceTime((DateUtil.between(new Date(), batteryMsgVO.getUpdateTime(), DateUnit.DAY)) + "天");
                }else {
                    batteryMsgVO.setResidenceTime((DateUtil.between(new Date(), batteryMsgVO.getAddTime(), DateUnit.DAY)) + "天");
                }
            }
        }
        String fileName = Objects.isNull(downloadDTO.getStartTime()) || Objects.isNull(downloadDTO.getEndTime()) ? "电池厂商信息" : String.format("%s~%s_电池厂商信息", DateUtil.formatDate(downloadDTO.getStartTime()), DateUtil.formatDate(downloadDTO.getEndTime()));
        ExcelUtil<BatteryMsgVO> excelUtil = new ExcelUtil<>(BatteryMsgVO.class);
        return Result.success(excelUtil.exportExcel(dataList, fileName).getData());
    }


    /**
     * 封装电池状态对象
     * @param login 登录账号信息
     * @param remark 备注
     * @param batteryVOList 电池集合
     * @param batteryMsgVO 封装对象
     * @param batteryType 修改类型
     */
    private void packBatteryVo(LoginInfo login, String remark, List<BatteryVO> batteryVOList, BatteryMsgVO batteryMsgVO, int batteryType) {
        //修改电池状态
        BatteryVO batteryVO = new BatteryVO();
        batteryVO.setAccountUserId(login.accountUserId)
                .setBatteryNo(batteryMsgVO.getBatteryNO())
                .setState(batteryType)
                .setUpdateTime(new Date())
                .setUserCode(Objects.nonNull(batteryMsgVO.getUserCode()) ? null : "1")
                .setRemark(remark);
        batteryVOList.add(batteryVO);
    }

    /**
     * 封装电池日志对象
     * @param login 登录账号信息
     * @param accountId 区域id
     * @param remark 备注
     * @param batteryLogList 电池操作日志集合
     * @param batteryMsgVO 对象
     * @param batteryLogType 电池日志类型
     */
    private void packBatteryLog(LoginInfo login, Integer accountId, String remark, List<BatteryLog> batteryLogList, BatteryMsgVO batteryMsgVO, int batteryLogType) {
        //电池日志
        BatteryLog batteryLog = new BatteryLog();
        batteryLog.setAccountId(accountId)
                .setAccountUserId(login.accountUserId)
                .setAddTime(new Date())
                .setBatteryId(Integer.parseInt(batteryMsgVO.getBatteryId()))
                .setBatteryNO(batteryMsgVO.getBatteryNO())
                .setType(batteryLogType)
                .setRemark(remark);
        batteryLogList.add(batteryLog);
    }

}
